<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>理解对象</title>
</head>

<body>
    <div class="part">
        <h1>6.1.1 属性类型</h1>
        <section>
            <h2>6.1.1.1 数据属性</h2>
            <ul>
                <li>
                    [[Configurable]]: 能否通过delete删除属性；能否修改属性特征；能否把属性修改为访问器属性。默认为true
                </li>
                <li>
                    [[Enumerable]]:能否通过for-in循环返回属性。默认为true
                </li>
                <li>
                    [[Writable]]:能否修改属性的值。默认为true
                </li>
                <li>
                    [[Value]]:包含该属性的数据值。默认undefined
                </li>
            </ul>
            <p>要修改属性默认的特征，使用Object.defineProperty()方法</p>
            <p>在调用Object.defineProperty方法时候，如果不指定Configurable、Enumerable、Writable；默认都是false。多数情况下，没有必要利用Object.defineProperty方法提供的这些高级功能。
            </p>
            <p>用new跟对象字面量定义的属性都属于数据类型。并且这些属性的Configurable、EnumerableWritable都被设定为true。</p>
            <div class="actions"><button onclick="handleCreateSimpleObject()">创建简单的Object对象</button>
                <button onclick="handleCreateLiteralObject()">创建对象字面量对象</button>
                <button onclick="handleGetOwnPropertyDescriptor()">获取person对象name的数据属性</button>
                <button onclick="handleDefinePropertyWritable()">修改属性默认的特征之writable</button>
                <button onclick="handleDefinePropertyConfigurable()">修改属性默认的特征之configuralbe</button>
                <button onclick="handleDefinePropertyConfigurable2()">修改属性默认的特征之configuralbe,设置false再配置</button>
            </div>
        </section>
        <section>
            <h2>6.1.1.2 访问器属性</h2>
            <ul>
                <li>
                    [[Configurable]]: 能否通过delete删除属性；能否修改属性特征；能否把属性修改为数据属性。默认为true
                </li>
                <li>
                    [[Enumerable]]:能否通过for-in循环返回属性。默认为true
                </li>
                <li>
                    [[Get]]:在读取属性时调用的函数。默认值为undefined
                </li>
                <li>
                    [[Set]]:在写入属性时调用的函数。默认值为undefined
                </li>
            </ul>
            <p>访问器属性不能直接定义，必须试用Object.defineProperty()</p>
            <p>使用访问器属性的常见方式，即设置一个属性的值会导致其他属性发生变化。（因为setter函数作用）</p>
            <p>不是非得同时要指定getter跟setter。只指定getter意味着属性不能写（如果写，非严格模式忽略，严格模式会抛错）；只指定setter意味着属性不可读（如果读，非严格undefined，严格抛错）。
            </p>
            <div class="actions">
                <button onclick="handleDefineAccessorAttribute()">定义访问器属性</button>
                <button onclick="handleDefineAccessorAttributeGetter()">定义访问器属性：getter</button>
                <button onclick="handleDefineAccessorAttributeSetter()">定义访问器属性：setter</button>
            </div>
        </section>
    </div>
    <div class="part">
        <h1>6.1.2 定义多个属性</h1>
        <section>
            <p>由于对象定义多个可能性很大，es5又定义了一个Object.defineProperties()的方法。该方法可以通过描述符一次性定义多个属性。</p>
            <p>该方法有两个参数：第一个是要添加和修改其属性的对象；第二个是需要添加跟修改的属性。</p>
            <button onclick="handleDefineAttributes()">定义多个属性</button>
        </section>
    </div>
    <div class="part">
        <h1>6.1.3 读取属性的特征</h1>
        <section>
            <p>ES5的Object.getOwnPropertyDescriptor()方法，可以取得给定属性的描述符。</p>
            <p>该方法有两个参数：第一个是属性所在的对象；第二个是要读取其描述符的属性。</p>
            <p>返回值：为一个对象，如果是访问器属性，这个对象的属性有configurable,enumberable,get和set；如果是数据属性，这个对象的属性有configurable,enumberable,writable,value
            </p>
            <button onclick="handleGetOwnPropertyDescriptor()">读取属性特征</button>
        </section>
    </div>
    <script>
        "use strict";
        // =======================================================================6.1.1.1 数据属性
        /**
         * handleCreateSimpleObject:创建简单的Object对象
         * */
        function handleCreateSimpleObject() {
            var person = new Object();
            person.name = "nick";
            person.age = 19;
            person.job = "teacher";

            person.sayName = function () {
                alert(this.name)
            }
            person.sayName()
            console.log("handleCreateSimpleObject", person)
        }
        /**
         * handleCreateLiteralObject:创建对象字面量的Object对象
         * */
        function handleCreateLiteralObject() {
            var person = {
                name: "nick",
                age: 19,
                job: "teacher",
                sayName: function () {
                    alert(this.name)
                }
            };
            person.sayName()
            console.log("handleCreateLiteralObject", person)
        }
        /**
        * handleGetOwnPropertyDescriptor:获取对象某个属性的数据属性
        * */
        function handleGetOwnPropertyDescriptor() {
            var person = {
                name: "nick",
                age: 19,
                job: "teacher",
                sayName: function () {
                    alert(this.name)
                }
            };
            const descriptor = Object.getOwnPropertyDescriptor(person, "name")
            console.log("handleGetOwnPropertyDescriptor", Object, descriptor)
        }
        /**
        * handleDefinePropertyWritable:修改属性默认的特征之writable
        * */
        function handleDefinePropertyWritable() {
            var person = {}
            Object.defineProperty(person, "name", {
                writable: false,
                value: "jack",
            })
            console.log("handleDefineProperty01", person.name)
            person.name = "lee"
            console.log("handleDefineProperty02", person.name)
        }
        /**
        * handleDefinePropertyConfigurable:修改属性默认的特征之configurable
        * */
        function handleDefinePropertyConfigurable() {
            var person = {}
            Object.defineProperty(person, "name", {
                configurable: false,
                value: "jack",
            })
            console.log("handleDefineProperty01", person.name)
            delete person.name
            console.log("handleDefineProperty02", person.name)
        }
        /**
       * handleDefinePropertyConfigurable2:修改属性默认的特征之configurable2
       * 一旦具体属性定义为不可配置的，就不能再把它变回可配置的了
       * */
        function handleDefinePropertyConfigurable2() {
            var person = {}
            Object.defineProperty(person, "name", {
                configurable: false,
                value: "jack",
            })
            Object.defineProperty(person, "name", {
                configurable: true,
                value: "jack",
            })
        }
        // ====================================================6.1.1.2 访问器属性
        /**
         * handleDefineAccessorAttribute 定义访问器属性 
         */
        function handleDefineAccessorAttribute() {
            var book = {
                _year: 2005, // 下划线是一种记号，表示只能通过对象方法访问的属性。
                edition: 1,
            }
            Object.defineProperty(book, "year", {
                get: function () {
                    return this._year
                },
                set: function (newValue) {
                    if (newValue > 2004) {
                        this._year = newValue
                        this.edition = newValue - 2004
                    }
                }
            })
            book.year = 2006
            console.warn("book", book)
        }
        /**
         * handleDefineAccessorAttributeGetter 定义访问器属性：getter
         */
        function handleDefineAccessorAttributeGetter() {
            var book = {}
            Object.defineProperty(book, "name", {
                get: function () {
                    return "《平凡的世界》"
                }
            })
            console.warn("book", book.name)
            book.name = "《人生》"
            console.warn("book", book.name)
        }
        /**
         * handleDefineAccessorAttributeSetter 定义访问器属性：getter
         */
        function handleDefineAccessorAttributeSetter() {
            var book = {}
            Object.defineProperty(book, "name", {
                set: function () {
                    this.name = "《人生》"
                }
            })
            console.warn("book", book.name)
        }
        // =====================================6.1.2 定义多个属性
        function handleDefineAttributes() {
            var book = {}
            Object.defineProperties(book, {
                _year: {
                    writable: true,
                    value: 2004,
                },
                edition: {
                    writable: true,
                    value: 1,
                },
                year: {
                    get: function () {
                        return this._year
                    },
                    set: function (newValue) {
                        if (newValue > 2004) {
                            this._year = newValue
                            this.edition = newValue - 2004
                        }
                    }
                }
            })
            console.warn("book", book)
        }
        // =============================================6.1.3 读取属性的特征
        function handleGetOwnPropertyDescriptor() {
            var book = {}
            Object.defineProperties(book, {
                _year: {
                    writable: true,
                    value: 2004,
                },
                edition: {
                    writable: true,
                    value: 1,
                },
                year: {
                    get: function () {
                        return this._year
                    },
                    set: function (newValue) {
                        if (newValue > 2004) {
                            this._year = newValue
                            this.edition = newValue - 2004
                        }
                    }
                }
            })
            var descriptor = Object.getOwnPropertyDescriptor(book, "_year")
            console.warn("descriptor", descriptor)
            var descriptor2 = Object.getOwnPropertyDescriptor(book, "year")
            console.warn("descriptor2", descriptor2)
        }
    </script>
</body>

</html>